package com.yuw.threaddemo;

/**
 * 仓库栈
 */
public class MyStack {
    // 栈使用数组来进行存储
    // 属性
    // 存储数组
    private Goods[] goodsStack;
    // 栈顶指针
    private int index;
    // 仓库栈的容量【数组的长度】
    private int stackCount;

    // 行为

    public MyStack(int stackCount) {
        this.stackCount = stackCount;
        // 初始化栈信息
        // 仓库容量不能为负值
        if (this.stackCount <= 0) {
            // 默认仓库容量为10
            this.stackCount = 10;
        }
        goodsStack = new Goods[this.stackCount];
        // 设置栈顶指针初始位置
        index = 0;
    }

    // 入栈

    /**
     * 入栈操作
     *
     * @param good 入栈的商品
     */
    public synchronized void push(Goods good) {
        // 将产品存入当前栈顶位置
        // 当仓库满的时候，让生产者自行挂起，生产者自动进入仓库的等待队列，等待消费者去消费仓库的商品
        if (index >= stackCount) {
            try {
                this.wait(); // 调用wait方法，当前生产者线程自动进入 挂起的等待队列，线程不再执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 如果仓库没有满，则继续生产产品入库，同时通知在仓库的消费者等待队列可以进行消费了
        goodsStack[index] = good;
        // 存入之后，栈顶位置向上移动一个单元
        index++;
        System.out.println("生产者生产了一个商品。。。");
        // 通知消费者等待队列可以消费了
        this.notifyAll();
    }

    // 出栈

    /**
     * 出栈操作
     *
     * @return 当前栈顶位置的商品对象
     */
    public synchronized Goods pop() {

        // 当仓库空的时候，让消费者自行挂起，消费者自动进入仓库的等待队列，等待生产者去生产仓库的商品
        if (index <= 0) {
            try {
                this.wait(); // 调用wait方法，当前消费者线程自动进入 挂起的等待队列，线程不再执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 栈顶位置向下移动一个单元
        index--;
        // 取出当前位置的商品
        Goods goods = goodsStack[index];
        // 将当前栈顶位置置空
        goodsStack[index] = null;
        System.out.println("消费者消费了一个商品。。。");
        // 如果仓库没有空，则继续消费产品出库，同时通知在仓库的生产者等待队列可以去生产了
        // 通知生产者等待队列的线程，可以进行生产了
        this.notifyAll();
        // 返回栈顶元素
        return goods;
    }
}
